package com.linkin.homepage.view;


import android.content.Context;
import android.util.AttributeSet;
import android.view.View;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.OrientationHelper;
import androidx.recyclerview.widget.RecyclerView;

public class FixedLinearLayoutManager extends LinearLayoutManager {

    private OrientationHelper mOrientationHelper;

    public FixedLinearLayoutManager(Context context) {
        super(context);
    }

    public FixedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public FixedLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public int computeVerticalScrollOffset(RecyclerView.State state) {
        if (getChildCount() == 0) {
            return 0;
        }
        ensureLayoutState();
        return computeScrollOffset(state,
                findFirstVisibleChildClosestToStart(),
                findFirstVisibleChildClosestToEnd());
    }

    @Override
    public int computeVerticalScrollRange(RecyclerView.State state) {
        if (getChildCount() == 0) {
            return 0;
        }
        ensureLayoutState();
        return computeScrollRange(state,
                findFirstVisibleChildClosestToStart(),
                findFirstVisibleChildClosestToEnd());
    }

    private int computeScrollOffset(RecyclerView.State state, View startChild, View endChild) {
        if (getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
                || endChild == null) {
            return 0;
        }
        final int minPosition = Math.min(getPosition(startChild), getPosition(endChild));
        final int itemsBefore = Math.max(0, minPosition);

        final int laidOutArea = Math.abs(mOrientationHelper.getDecoratedEnd(endChild) - mOrientationHelper.getDecoratedStart(startChild));
        final int itemRange = Math.abs(getPosition(startChild) - getPosition(endChild)) + 1;
        final float avgSizePerRow = (float) laidOutArea / itemRange;

        float offset = (mOrientationHelper.getStartAfterPadding() - mOrientationHelper.getDecoratedStart(startChild));
        if (avgSizePerRow > 0 && startChild.getHeight() > 0) {
            offset = avgSizePerRow * offset / startChild.getHeight();
        }
        return Math.round(itemsBefore * avgSizePerRow + offset);
    }

    private int computeScrollRange(RecyclerView.State state, View startChild, View endChild) {
        if (getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
                || endChild == null) {
            return 0;
        }

        // smooth scrollbar enabled. try to estimate better.
        final int laidOutArea = Math.abs(mOrientationHelper.getDecoratedEnd(endChild) - mOrientationHelper.getDecoratedStart(startChild));
        final int laidOutRange = Math.abs(getPosition(startChild) - getPosition(endChild)) + 1;

        // estimate a size for full list.
        if (laidOutRange == 1 && state.getItemCount() == 2) {
            return (int) ((float) laidOutArea / laidOutRange * 1);
        }
        return (int) ((float) laidOutArea / laidOutRange * state.getItemCount());
    }

    private View findFirstVisibleChildClosestToStart() {
        return findOneVisibleChild(0, getChildCount());
    }

    private View findFirstVisibleChildClosestToEnd() {
        return findOneVisibleChild(getChildCount() - 1, -1);
    }

    private void ensureLayoutState() {
        if (mOrientationHelper == null) {
            mOrientationHelper = OrientationHelper.createOrientationHelper(this, getOrientation());
        }
    }

    private View findOneVisibleChild(int fromIndex, int toIndex) {
        ensureLayoutState();
        final int start = mOrientationHelper.getStartAfterPadding();
        final int end = mOrientationHelper.getEndAfterPadding();
        final int next = toIndex > fromIndex ? 1 : -1;
        for (int i = fromIndex; i != toIndex; i+=next) {
            final View child = getChildAt(i);
            final int childStart = mOrientationHelper.getDecoratedStart(child);
            final int childEnd = mOrientationHelper.getDecoratedEnd(child);

            if (childStart < end && childEnd > start) {
                return child;
            }
        }
        return null;
    }
}
